Skip to content

Confirm Invitations#32

Open
Katzenkralle wants to merge 4 commits intonumberly:mainfrom
Katzenkralle:invide_confirmation
Open

Confirm Invitations#32
Katzenkralle wants to merge 4 commits intonumberly:mainfrom
Katzenkralle:invide_confirmation

Conversation

@Katzenkralle
Copy link
Contributor

When Vaultwarden is configured with INVITATIONS_ALLOWED="false", users invited to an organization must be confirmed before their access to the organization is granted.
This adds a .confirm(user) method to the Organization class that allows us to do that.

@pascalmtts
Copy link

Why is this not merged yet? Would be super handy.

@Lujeni
Copy link
Member

Lujeni commented Feb 17, 2026

Why is this not merged yet? Would be super handy.

Hi @pascalmtts like many OSS projects, we do our best to review and maintain our codebase. This project is especially sensitive since it’s security-related, so we review changes more carefully than usual.

I’ll start the review later this week. On a personal note, have you had a chance to test this MR in an environment? Any feedback would also help move the merge forward.

@Lujeni Lujeni self-assigned this Feb 17, 2026
@Lujeni Lujeni added the enhancement New feature or request label Feb 17, 2026
method, path, headers=headers, **kwargs
)

def get_public_key_for_user(self, user_id: UUID | None = None) -> str:
Copy link
Member

@Lujeni Lujeni Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get(publickey) returns None if the key is missing, but the return type is str. This None will then be passed to the others functions (b64) and will will raise an opaque excepton. You should explicitly check and raise a meaningful error (e.g. BitwardenError("User has no public key")).

)

def get_public_key_for_user(self, user_id: UUID | None = None) -> str:
used_id = user_id if user_id else self.sync().Profile.Id
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you kept the same naming variable user_id pls

def confirm(
self,
new_user: OrganizationUserDetails,
):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a docstrings pls and return type is not annotated pls

new_user: OrganizationUserDetails,
):
rsa_public_key_new_user = b64decode(
self.api_client.get_public_key_for_user(new_user.UserId)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's None here, get_public_key_for_user(None) falls back to
self.sync().Profile.Id )the calling user's own public key?)

This means the organization key would be encrypted for the wrong user, potentially leaking it ?

resp = self.organization.invite("test-account-3@example.com")
self.assertTrue(resp.is_success)

if not os.environ.get("VAULTWARDEN_INVITATIONS_ALLOWED", "True").lower() in ["true", "1", "yes"]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VAULTWARDEN_INVITATIONS_ALLOWED is already explicitly set in the test script, do we really need to recheck it here?


Not related to this MR, we consider refactoring the entire test setup so we can more easily handle cases where we want to run the same tests with different variables. Ideally, this would integrate cleanly with pytest.mark and testcontainers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request waiting

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants